package jp.tkym.labs.rpc;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Method;

import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

class RemoteServiceServlet<SV> implements Servlet{
	private Class<? extends SV> serviceImplClass;
	private SV service;
	private ServletConfig config;
	RemoteServiceServlet(Class<? extends SV> serviceImplClass){
		this.serviceImplClass = serviceImplClass;
	}
	
	@Override
	public void init(ServletConfig config) throws ServletException {
		if(service!=null) return;
		try {
			service = serviceImplClass.newInstance();
		} catch (Exception e) {
			throw new ServletException(e);
		}
		this.config = config;
	}

	@Override
	public ServletConfig getServletConfig() {
		return this.config;
	}

	@Override
	public void service(ServletRequest req, ServletResponse res)
			throws ServletException, IOException {
		ObjectInputStream ois = new ObjectInputStream(req.getInputStream());
		ObjectOutputStream oos = new ObjectOutputStream(res.getOutputStream());
		try {
			RpcBean query = (RpcBean) ois.readObject();
			RpcBean result = processRpc(query);
			oos.writeObject(result);
		} catch (ClassNotFoundException e) {
			throw new ServletException(e);
		}
	}
	
	RpcBean processRpc(RpcBean bean){	
		String methodName = bean.getMethodName();
		String[] typeNames = bean.getParameterTypes();
		Class<?>[] typeClasses = new Class<?>[typeNames.length];
		try {
			for(int i=0; i<typeNames.length; i++)
				typeClasses[i] = Class.forName(typeNames[i]);
			Method method = serviceImplClass.getMethod(methodName, typeClasses);
			Object[] args = bean.getParameters();
			Object result = method.invoke(service, args);
			bean.setResult(result);
			bean.setParameters(args);
		} catch (Exception e) {
			bean.setException(e);
			return bean;
		}
		return bean;
	}
	
	@Override
	public String getServletInfo() {
		System.out.println("@Server:ServletInfo()");
		return null;
	}

	@Override
	public void destroy() {
		System.out.println("@Server:destroy()");
	}
}